package com.yuandian.management.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yuandian.api.management.entity.ConfMpAbility;
import com.yuandian.api.management.entity.ConfMpService;
import com.yuandian.api.management.po.ConfMpAlarmParams;
import com.yuandian.api.management.po.ConfMpServiceParams;
import com.yuandian.api.management.vo.OptionVo;
import com.yuandian.bpm.common.core.util.R;
import com.yuandian.enums.MajorDimensionEnum;
import com.yuandian.enums.SubDimensionEnum;
import com.yuandian.management.mapper.ConfMpServiceMapper;
import com.yuandian.management.service.ConfMpAlarmService;
import com.yuandian.management.service.ConfMpResourceService;
import com.yuandian.management.service.ConfMpReturnCodeService;
import com.yuandian.management.service.ConfMpServiceService;
import com.yuandian.utils.MpGenUtil;
import com.yuandian.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 中台监控-服务配置表-Service实现
 * @author zfsn
 * @date 2023-4-18
 */
@Service
public class ConfMpServiceServiceImpl extends ServiceImpl<ConfMpServiceMapper, ConfMpService>
		implements ConfMpServiceService {

	@Autowired
	private ConfMpAlarmService confMpAlarmService;

	@Autowired
	private ConfMpResourceService confMpResourceService;

	@Autowired
	private ConfMpReturnCodeService confMpReturnCodeService;

	@Autowired
	private ConfMpServiceMapper confMpServiceMapper;

	/**
	 * 根据服务编码获取一条服务配置数据
	 * @param serviceCode 服务编码
	 * @return 服务配置实体
	 */
	private ConfMpService getByServiceCode(String serviceCode) {
		return lambdaQuery().eq(ConfMpService::getServiceCode, serviceCode).one();
	}

	/**
	 * 分页查询
	 * @param params 中台监控-服务配置请求参数
	 * @return 通用返回对象
	 */
	@Override
	public R page(ConfMpServiceParams params) {
		Page<ConfMpService> page = Page.of(params.getCurrent(), params.getSize());
		//获取能力服务列表
		List<ConfMpService> list = null;
		if (StrUtil.isNotBlank(params.getUrl()) || StrUtil.isNotBlank(params.getResourceCode())) {
			list  = confMpServiceMapper.selectAbilityServerByResource(page, params);
		} else {
			list = confMpServiceMapper.selectAbilityServer(page, params);
		}
        if (list != null && list.size() > 0) {
			//获取单位编码及单位名称
			Map<String,String> orgMap = getOrg();

			//获取系统ID及单位编码
			Map<Integer, ConfMpAbility> sysOrgMap = new HashMap<>();
			List<ConfMpAbility> sysOrgList = confMpServiceMapper.selectAbility();
            if (sysOrgList != null && sysOrgList.size() > 0) {
				for (ConfMpAbility cma : sysOrgList) {
					sysOrgMap.put(cma.getId(), cma);
				}
			}
			//获取系统ID及系统名称
			Map<Integer, String> systemMap = new HashMap<>();
			List<Map<String, String>> sysListMap = confMpServiceMapper.selectSystem();
            if (sysListMap != null && sysListMap.size() > 0) {
				for (Map<String, String> map : sysListMap) {
					systemMap.put(Integer.valueOf(String.valueOf(map.get("id"))), map.get("name"));
				}
			}

			ConfMpAbility confMpAbility = null;
			for (ConfMpService cs : list) {
				//获取能力对象
				confMpAbility = sysOrgMap.get(cs.getAbilityId());
				if (confMpAbility != null) {
					cs.setSystemId(confMpAbility.getSystemId() + "");
					cs.setOrgCode(confMpAbility.getOrgCode());
					cs.setOrgName(orgMap.get(confMpAbility.getOrgCode()));
					cs.setSystemName(systemMap.get(confMpAbility.getSystemId()));
				}

				// 根据 ‘,’ 切割 副量纲subDimension 字符串
				if (StringUtils.isNotEmpty(cs.getSubDimension())) {
					cs.setSubDimensionList(Arrays.asList(cs.getSubDimension().split(",")));
				}
			}
		}
        //page.addOrder(params.orders()).orders().forEach(orderItem -> orderItem.setColumn(StrUtil.toUnderlineCase(orderItem.getColumn())));
		//return R.ok(lambdaQuery()
		//		.eq(params.getAbilityId() != null, ConfMpService::getAbilityId, params.getAbilityId())
		//		.eq(StrUtil.isNotEmpty(params.getServiceCode()), ConfMpService::getServiceCode, params.getServiceCode())
		//		.like(StrUtil.isNotEmpty(params.getServiceName()), ConfMpService::getServiceName, params.getServiceName())
		//		.page(page));

		page.setRecords(list);
		return R.ok(page);
	}

	/**
	 * 新增数据
	 * @param params 中台监控-服务配置请求参数
	 * @return 通用返回对象
	 */
	@Transactional(rollbackFor = Exception.class)
	@Override
	public R<Boolean> saveWrap(ConfMpServiceParams params) {
		// 1、校验服务编码的唯一性
		if (ObjectUtil.isNotNull(getByServiceCode(params.getServiceCode()))) {
			return R.failed("新增失败，已存在相同的服务编码！");
		}
		// 2、切分能力所属的中台
		String serverCode = params.getServiceCode();
		// 能力编码中，所属中台：第二位
		params.setMiddlePlatformId(serverCode.substring(1, 2));;
		// 3、新增服务配置
		ConfMpService confMpService = BeanUtil.copyProperties(params, ConfMpService.class);
		save(confMpService);
		// 4、新增默认的告警配置
		Integer serviceId = confMpService.getId();
		List<ConfMpAlarmParams> alarmParamsList = MpGenUtil.genDefaultAlarm(params.getInvocationMode(), serviceId);
		alarmParamsList.forEach(alarmParams -> confMpAlarmService.saveWrap(alarmParams));
		return R.ok(Boolean.TRUE, "新增成功");
	}

	/**
	 * 通过主键更新数据
	 * @param params 中台监控-服务配置请求参数
	 * @return 通用返回对象
	 */
	@Transactional(rollbackFor = Exception.class)
	@Override
	public R<Boolean> updateByIdWrap(ConfMpServiceParams params) {
		// 1、校验请求参数
		Integer serviceId = params.getId();
		if (serviceId == null) {
			return R.failed("更新失败，服务id不能为空！");
		}
		// 2、通过id获取服务配置
		ConfMpService serviceById = getById(serviceId);
		// 3、校验该配置是否存在
		if (ObjectUtil.isNull(serviceById)) {
			return R.failed("更新失败，不存在该服务配置！");
		}
		/*
		 * 4、校验服务编码的唯一性
		 * 通过服务编码获取服务配置如果为空，说明不存在相同的服务编码，
		 * 或者不为空，但id和要修改的服务配置的id一样，说明修改的是自己的服务编码，这也是唯一的，
		 * 所以这里的判断条件是：当通过服务编码获取服务配置不为空且id不一致时，认为存在相同的服务编码
		 */
		ConfMpService serviceByCode = getByServiceCode(params.getServiceCode());
		if (ObjectUtil.isNotNull(serviceByCode) && !serviceId.equals(serviceByCode.getId())) {
			return R.failed("更新失败，已存在相同的服务编码！");
		}
		// 5、更新服务配置
		String invocationMode = serviceById.getInvocationMode();
		// 6、切分能力所属的中台
		String serverCode = params.getServiceCode();
		// 能力编码中，所属中台：第二位
		params.setMiddlePlatformId(serverCode.substring(1, 2));;
		BeanUtil.copyProperties(params, serviceById);
		updateById(serviceById);
		// 7、如果服务调用模式发生改变，需要调整告警配置
		if (!invocationMode.equals(params.getInvocationMode())) {
			confMpAlarmService.updateByService(serviceById);
		}
		return R.ok(Boolean.TRUE, "更新成功");
	}

	/**
	 * 通过主键删除数据
	 * @param idList 主键集合
	 * @return 通用返回对象
	 */
	@Transactional(rollbackFor = Exception.class)
	@Override
	public R<Boolean> removeByIdsWrap(List<Integer> idList) {
		// 1、校验请求参数
		if (CollUtil.isEmpty(idList)) {
			return R.failed("删除失败，主键集合不能为空");
		}
		// 2、根据服务id集合删除服务下的所有告警配置
		confMpAlarmService.removeByServiceIds(idList);
		// 3、根据服务id集合删除服务下的所有资源配置
		confMpResourceService.removeByServiceIds(idList);
		// 4、根据服务id集合删除服务下的所有返回码配置
		confMpReturnCodeService.removeByServiceIds(idList);
		// 5、删除服务配置
		removeByIds(idList);
		return R.ok(Boolean.TRUE, "删除成功");
	}

	/**
	 * 根据能力id集合删除能力下的所有服务配置
	 * @param abilityIdList 能力id集合
	 * @return 通用返回对象
	 */
	@Transactional(rollbackFor = Exception.class)
	@Override
	public R<Boolean> removeByAbilityIds(List<Integer> abilityIdList) {
		// 1、根据能力id集合查询所有的服务配置
		List<ConfMpService> serviceList = lambdaQuery()
				.in(CollUtil.isNotEmpty(abilityIdList), ConfMpService::getAbilityId, abilityIdList).list();
		// 2、获取所有服务配置的id
		List<Integer> serviceIdList = serviceList.stream().map(ConfMpService::getId).collect(Collectors.toList());
		// 3、通过主键删除服务配置
		return removeByIdsWrap(serviceIdList);
	}

	/**
	 * 查询服务选项
	 * @return 通用返回对象
	 */
	@Override
	public R<List<OptionVo>> option(Integer abilityId) {
		List<ConfMpService> serviceList = lambdaQuery().select(
				ConfMpService::getId, ConfMpService::getServiceCode, ConfMpService::getServiceName)
				.eq(abilityId != 0, ConfMpService::getAbilityId, abilityId).list();
		List<OptionVo> list = new ArrayList<>();
		serviceList.forEach(service -> {
			OptionVo vo = new OptionVo();
			vo.setLabel(service.getServiceName());
			vo.setValue(service.getServiceCode());
			vo.setId(service.getId());
			list.add(vo);
		});
		return R.ok(list);
	}

	/**
	 * 获取所有的单位编码及单位名称
	 * @return
	 */
	@Override
	public Map<String, String> getOrg() {
		Map<String,String> orgMap = new HashMap<String, String>();
		List<Map<String,String>> listMap = confMpServiceMapper.selectOrg();
		if (listMap != null && listMap.size() > 0) {
			for (Map<String,String> map : listMap) {
				orgMap.put(map.get("org_code"), map.get("org_name"));
			}
		}
		return orgMap;
	}

	/**
	 * 更新服务量纲信息
	 * @param confMpService 服务对象
	 */
	@Override
	public R<Object> updateDimensionById(ConfMpService confMpService) {
		// 参数校验
		if (confMpService.getId() == null) { return R.failed("更新失败，主键不能为空"); }

		if (StringUtils.isBlank(confMpService.getMajorDimension())) { return R.failed("更新失败，主量纲不能为空"); }

		if (CollectionUtil.isNotEmpty(confMpService.getSubDimensionList()) &&
				confMpService.getSubDimensionList().contains(confMpService.getMajorDimension())) {

			return R.failed("更新失败，主量纲和副量纲不能相同");
		}

		// 拼接父量纲
		if(CollectionUtil.isNotEmpty(confMpService.getSubDimensionList())) {
			confMpService.setSubDimension(String.join(",", confMpService.getSubDimensionList()));
		}

		// 更新量纲信息
		int effectCount = confMpServiceMapper.updateDimensionById(confMpService);

		return effectCount > 0 ? R.ok(Boolean.TRUE, "更新成功") : R.failed("更新失败");

	}

	/**
	 * 查询主量纲下拉框
	 * @return 通用返回对象
	 */
	@Override
	public R<List<OptionVo>> majorDimensionOption() {
		List<OptionVo> resultList = new ArrayList<>();
		for (MajorDimensionEnum majorDimension : MajorDimensionEnum.values()) {
			OptionVo optionVo = new OptionVo();
			optionVo.setLabel(majorDimension.getMsg());
			optionVo.setValue(majorDimension.getCode());
			resultList.add(optionVo);
		}
		return R.ok(resultList);

	}

	/**
	 * 查询副量纲下拉框
	 * @return 通用返回对象
	 */
	@Override
	public R<List<OptionVo>> subDimensionOption() {
		List<OptionVo> resultList = new ArrayList<>();
		for (SubDimensionEnum subDimension : SubDimensionEnum.values()) {
			OptionVo optionVo = new OptionVo();
			optionVo.setLabel(subDimension.getMsg());
			optionVo.setValue(subDimension.getCode());
			resultList.add(optionVo);
		}
		return R.ok(resultList);
	}

}